package com.linking.third.party.manager;

import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.linking.third.party.pojo.bo.MycardPayBO;
import com.linking.third.party.pojo.bo.MycardPayConfirmBO;
import com.linking.third.party.pojo.bo.MycardPayResBO;
import com.linking.third.party.pojo.bo.MycardPayVerifyBO;
import com.linking.third.party.pojo.bo.ReceiptVerifyBO;
import java.math.BigDecimal;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;

/**
 * @Author YaoWeiXin
 * @Date 2020/9/16 17:47
 * @Description mycard 管理类
 */
@Slf4j
public class MycardManager {

  private final static String TEST_AUTH_URL = "https://testb2b.mycard520.com.tw/MyBillingPay/v1.1/AuthGlobal";
  private final static String PROD_AUTH_URL = "https://b2b.mycard520.com.tw/MyBillingPay/v1.1/AuthGlobal";

  private final static String TEST_TRADE_URL = "https://testb2b.mycard520.com.tw/MyBillingPay/v1.1/TradeQuery";
  private final static String PROD_TRADE_URL = "https://b2b.mycard520.com.tw/MyBillingPay/v1.1/TradeQuery";

  private final static String TEST_PAYMENT_CONFIRM_URL = "https://testb2b.mycard520.com.tw/MyBillingPay/v1.1/PaymentConfirm";
  private final static String PROD_PAYMENT_CONFIRM_URL = "https://b2b.mycard520.com.tw/MyBillingPay/v1.1/PaymentConfirm";

  /**
   * 创建支付
   *
   * @param mycardPay mycard支付参数
   * @return 创建结果
   */
  public static MycardPayResBO doPay(MycardPayBO mycardPay) {
    boolean sendBox = mycardPay.getSendBox();
    String url = sendBox ? TEST_AUTH_URL : PROD_AUTH_URL;
    String facServiceId = mycardPay.getAppId();
    String facTradeSeq = mycardPay.getOrderId();
    String tradeType = mycardPay.getPayType().name;
    String serverId = mycardPay.getServerId();
    String customerId = mycardPay.getUserId();
    String itemCode = mycardPay.getProductId();
    String productName =
        StrUtil.isEmpty(mycardPay.getProductDesc()) ? "" : mycardPay.getProductDesc();
    String amount = mycardPay.getAmount().toPlainString();
    String currency = mycardPay.getCurrency();
    String sandBoxMode = sendBox + "";
    String facReturnUrl = StrUtil.isEmpty(mycardPay.getReturnUrl()) ? "" : mycardPay.getReturnUrl();

    Map<String, Object> params = Maps.newHashMap();
    params.put("FacServiceId", facServiceId);
    params.put("FacTradeSeq", facTradeSeq);
    params.put("TradeType", tradeType);
    params.put("ServerId", serverId);
    params.put("CustomerId", customerId);
    params.put("ItemCode", itemCode);
    params.put("ProductName", productName);
    params.put("Amount", amount);
    params.put("Currency", currency);
    params.put("SandBoxMode", sandBoxMode);
    params.put("FacReturnURL", facReturnUrl);

    if (sendBox) {
      log.debug("params====================={}", JSON.toJSONString(params));
    }
    String preHashValue =
        facServiceId + facTradeSeq + tradeType + serverId + customerId + itemCode + URLUtil
            .encodeAll(productName).toLowerCase()
            + amount + currency + sandBoxMode + URLUtil.encodeAll(facReturnUrl).toLowerCase()
            + mycardPay.getPrivateKey();
    if (sendBox) {
      log.debug("preHashValue====================={}", preHashValue);
    }
    params.put("Hash", sha256(preHashValue));
    if (sendBox) {
      log.debug("Hash params====================={}", JSON.toJSONString(params));
    }
    String response = HttpUtil.post(url, params, 5000);
    if (sendBox) {
      log.debug("response====================={}", response);
    }
    if (StrUtil.isEmpty(response)) {
      return MycardPayResBO.ofFail();
    }
    JSONObject data = JSON.parseObject(response);
    String ok = "1";
    String returnCode = "ReturnCode";
    if (!ok.equals(data.getString(returnCode))) {
      log.debug("mycard do pay fail==========={}", data.getString("ReturnMsg"));
      return MycardPayResBO.ofFail();
    }
    String authCode = data.getString("AuthCode");
    String tradeSeq = data.getString("TradeSeq");
    return MycardPayResBO.of(authCode, tradeSeq);
  }

  /**
   * 票据验证
   *
   * @param mycardPayVerify mycard票据验证参数
   * @return 票据验证结果
   */
  public static ReceiptVerifyBO receiptVerify(MycardPayVerifyBO mycardPayVerify) {
    boolean sendBox = mycardPayVerify.getSendBox();
    // 1、组合参数
    String url = mycardPayVerify.getSendBox() ? TEST_TRADE_URL : PROD_TRADE_URL;
    Map<String, Object> params = Maps.newHashMap();
    params.put("AuthCode", mycardPayVerify.getAuthCode());
    if (sendBox) {
      log.debug("mycard receiptVerify=params===================={},{}", url, JSON.toJSONString(params));
    }
    // 2、请求校验
    String response = HttpUtil.post(url, params, 5000);
    if (sendBox) {
      log.debug("mycard receiptVerify=response===================={}", response);
    }
    if (StrUtil.isEmpty(response)) {
      return ReceiptVerifyBO.ofFail();
    }
    // 3、判断支付状态
    JSONObject data = JSON.parseObject(response);
    String ok = "1";
    String payOk = "3";
    String returnCode = "ReturnCode";
    String payResult = "PayResult";
    if (!ok.equals(data.getString(returnCode)) || !payOk.equals(data.getString(payResult))) {
      log.debug("mycard receiptVerify fail==========={}", data.getString("ReturnMsg"));
      return ReceiptVerifyBO.ofFail();
    }
    // 4、判断订单
    String facTradeSeq = data.getString("FacTradeSeq");
    if (!mycardPayVerify.getOrderId().equals(facTradeSeq)) {
      log.debug("mycard receiptVerify order fail==========={},{}", facTradeSeq,
          mycardPayVerify.getOrderId());
      return ReceiptVerifyBO.ofFail();
    }
    // 5、判断金额
    String amount = data.getString("Amount");
    if (mycardPayVerify.getAmount().compareTo(new BigDecimal(amount)) != 0) {
      log.debug("mycard receiptVerify amount fail==========={},{}", amount,
          mycardPayVerify.getAmount());
      return ReceiptVerifyBO.ofFail();
    }
    // 6、返回结果
    String paymentType = data.getString("PaymentType");
    String currency = data.getString("Currency");
    String myCardTradeNo = data.getString("MyCardTradeNo");
    return ReceiptVerifyBO.ofMycard(true, paymentType, currency, myCardTradeNo);
  }

  /**
   * 支付确认
   *
   * @param mycardPayConfirm mycard支付确认参数
   * @return 票据验证结果
   */
  public static Boolean paymentConfirm(MycardPayConfirmBO mycardPayConfirm) {
    boolean sendBox = mycardPayConfirm.getSendBox();
    // 1、组合参数
    String url =
        mycardPayConfirm.getSendBox() ? TEST_PAYMENT_CONFIRM_URL : PROD_PAYMENT_CONFIRM_URL;
    Map<String, Object> params = Maps.newHashMap();
    params.put("AuthCode", mycardPayConfirm.getAuthCode());
    if (sendBox) {
      log.debug("mycard paymentConfirm=params===================={},{}", url, JSON.toJSONString(params));
    }
    // 2、请求校验
    String response = HttpUtil.post(url, params, 5000);
    if (sendBox) {
      log.debug("mycard paymentConfirm=response===================={}", response);
    }
    if (StrUtil.isEmpty(response)) {
      return false;
    }
    // 3、判断支付状态
    JSONObject data = JSON.parseObject(response);
    String ok = "1";
    String returnCode = "ReturnCode";
    if (!ok.equals(data.getString(returnCode))) {
      log.debug("mycard paymentConfirm fail==========={}", data.getString("ReturnMsg"));
      return false;
    }
    // 4、返回结果
    return true;
  }

  /**
   * SHA-256
   */
  public static String sha256(String strSrc) {
    MessageDigest md;
    String strDes;
    byte[] bt = strSrc.getBytes();
    try {
      md = MessageDigest.getInstance("SHA-256");
      md.update(bt);
      // to HexString
      strDes = bytes2Hex(md.digest());
    } catch (NoSuchAlgorithmException e) {
      return null;
    }
    return strDes.toLowerCase();
  }

  public static String bytes2Hex(byte[] bts) {
    StringBuilder des = new StringBuilder();
    String tmp;
    for (byte bt : bts) {
      tmp = (Integer.toHexString(bt & 0xFF));
      if (tmp.length() == 1) {
        des.append("0");
      }
      des.append(tmp);
    }
    return des.toString();
  }

}
